import random, string, time, uuid
from django.db import models
from django.forms import ModelForm

# Things needed from NoPBX
#from nopbx.core.models import Module
#from nopbx.core.models import Network, Server
from nopbx.core.models import BaseModule, BaseOption
from nopbx.dialplan.models import Extension
from nopbx.infrastructure.models import Location



###############################################################################
#
# Lookup table of Device Types
#
class DeviceTypeManager(models.Manager):
    def get_by_natural_key(self, name):
        return self.get(name = name)

class DeviceType(BaseModule):
    name        = models.CharField(max_length = 50, unique = True)

    objects = DeviceTypeManager()
    class Meta:
        ordering = ['name']

    # Functions
    def __unicode__(self):
        return self.name

    def natural_key(self):
        return self.name



###############################################################################
#
# Lookup table of Manufacturers
#
class ManufacturerManager(models.Manager):
    def get_by_natural_key(self, name):
        return self.get(name = name)

class Manufacturer(BaseModule):
    name        = models.CharField(max_length = 50, unique = True)

    objects = ManufacturerManager()
    class Meta:
        ordering = ['name']

    # Functions
    def __unicode__(self):
        return self.name

    def natural_key(self):
        return self.name



###############################################################################
#
# Lookup table of Models
#
class ModelManager(models.Manager):
    def get_by_natural_key(self, name, manufacturer):
        return self.get(name = name, manufacturer = manufacturer)

class Model(BaseModule):
    name        = models.CharField(max_length = 50)

    device_type  = models.ForeignKey(DeviceType)
    manufacturer = models.ForeignKey(Manufacturer)
    max_lines    = models.PositiveIntegerField()

    # Default values (Override in the actual device configuration)
    firmware         = models.CharField(max_length = 50, blank = True, null = True)
    dial_template    = models.CharField(max_length = 100, blank = True, null = True)
    softkey_template = models.CharField(max_length = 100, blank = True, null = True)

    url_auth      = models.URLField(verify_exists = False, blank = True, null = True)
    url_directory = models.URLField(verify_exists = False, blank = True, null = True)
    url_idle      = models.URLField(verify_exists = False, blank = True, null = True)
    url_info      = models.URLField(verify_exists = False, blank = True, null = True)
    url_messages  = models.URLField(verify_exists = False, blank = True, null = True)

    objects = ModelManager()
    class Meta:
        ordering = ['name']
        unique_together = ('name', 'manufacturer')

    # Functions
    def __unicode__(self):
        return '%s - %s' % (self.manufacturer, self.name) 

    def natural_key(self):
        return (self.name, self.manufacturer)



###############################################################################
#
# Abstract class to build devices on
#
class DeviceManager(models.Manager):
    def get_by_natural_key(self, name):
        return self.get(name = name)

class Device(BaseModule):
    mac_address = models.CharField("MAC Address", max_length = 12, unique = True)
    enabled     = models.BooleanField(default = True)
    model       = models.ForeignKey(Model)
    serial      = models.CharField(max_length = 50, blank = True, null = True)
    asset_tag   = models.CharField(max_length = 50, blank = True, null = True)
#    context     = models.ForeignKey(Context, limit_choices_to = {'context_type': 2})
    location    = models.ForeignKey(Location)

    # Default values (Override in the actual device configuration)
    firmware         = models.CharField(max_length = 50, blank = True, null = True)
    dial_template    = models.CharField(max_length = 100, blank = True, null = True)
    softkey_template = models.CharField(max_length = 100, blank = True, null = True)

    url_auth      = models.URLField(verify_exists = False, blank = True, null = True, verbose_name = 'authentication', help_text = 'Request authentication URL')
    url_directory = models.URLField(verify_exists = False, blank = True, null = True, verbose_name = 'directory',      help_text = 'Phone directory URL')
    url_idle      = models.URLField(verify_exists = False, blank = True, null = True, verbose_name = 'idle',           help_text = 'URL to display when the device is Idle.')
    url_info      = models.URLField(verify_exists = False, blank = True, null = True, verbose_name = 'information',    help_text = 'Context-sensitive help URL.')
    url_messages  = models.URLField(verify_exists = False, blank = True, null = True, verbose_name = 'messages')

    objects = DeviceManager()
    class Meta:
        ordering = ['mac_address']

    # Functions
    def natural_key(self):
        return self.mac_address

    # Functions
    def __unicode__(self):
        return self.mac_address

    def version(self):
        """ Return a version string (modified time as epoch) """
        return int(time.mktime(self.modified.timetuple()) * 1000)

    def save(self, force_insert = False, force_update = False):
        """ 
        Override of the default save with:
         - Force the mac_address field to be upper case on save
        """
        self.mac_address = self.mac_address.upper()
        super(Device, self).save(force_insert, force_update)

class DeviceGeneralForm(ModelForm):
    """ 
    Form used for editing devices
    """
    class Meta:
        model = Device
        fields = ('mac_address', 'description', 'model', 'location')



###############################################################################
#
#
#
class LineManager(models.Manager):
    def get_by_natural_key(self, username):
        return self.get(username = username)

class Line(BaseModule):
    # Unique username / password for this line (as the device could change)
    username    = models.CharField(max_length = 50, unique = True)
    password    = models.CharField(max_length = 50)

    device      = models.ForeignKey(Device)
    index       = models.PositiveSmallIntegerField(default = 1, verbose_name = 'Line Number')

    exten       = models.ForeignKey(Extension)
    label       = models.CharField(max_length = 50)
    caller_id   = models.CharField(max_length = 100, blank = True, null = True, verbose_name = 'Caller ID')

    objects = LineManager()
    class Meta:
        ordering = ['index']
        unique_together = ('device', 'index')

    def natural_key(self):
        return  self.username

    def __unicode__(self):
        return self.username 

    def save(self, force_insert = False, force_update = False):
        """
        Override the default save routine to add some magic to generate a random username and password.
        """
        if (self.username == ""):
            u = uuid.uuid1()
            self.username = u.hex

        if (self.password == ""):
            password = [random.choice(string.letters) for x in xrange(20)]
            self.password = "".join(password)

        super(Line, self).save(force_insert, force_update)

class LineForm(ModelForm):
    class Meta:
        model = Line
        fields = ('device', 'index', 'exten', 'label', 'caller_id')

